Passed
Branch master (0c09a6)
by Stephan
01:45
created

tooltip.js ➔ ?!?   C

Complexity

Conditions 7
Paths 64

Size

Total Lines 897
Code Lines 537

Duplication

Lines 42
Ratio 4.68 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 537
nc 64
nop 3
dl 42
loc 897
rs 5.6
c 1
b 0
f 0

38 Functions

Rating   Name   Duplication   Size   Complexity  
A tooltip.js ➔ ... ➔ _getOffset 0 16 2
A tooltip.js ➔ ... ➔ _fixTransition 0 14 2
A tooltip.js ➔ ... ➔ getTitle 0 9 3
A tooltip.js ➔ ... ➔ disable 0 3 1
A tooltip.js ➔ ... ➔ _defineProperties 0 9 3
A tooltip.js ➔ ... ➔ toggleEnabled 0 3 1
A tooltip.js ➔ ... ➔ _getContainer 0 11 3
A tooltip.js ➔ ... ➔ _handlePopperPlacementChange 0 8 1
A tooltip.js ➔ ... ➔ update 0 5 2
A tooltip.js ➔ ... ➔ _fixTitle 0 8 3
A tooltip.js ➔ ... ➔ enable 0 3 1
A tooltip.js ➔ ... ➔ getTipElement 0 4 1
A tooltip.js ➔ ... ➔ isWithContent 0 3 1
A tooltip.js ➔ ... ➔ allowedAttribute 0 23 5
A tooltip.js ➔ ... ➔ _isWithActiveTrigger 0 9 3
D tooltip.js ➔ ... ➔ show 0 97 12
A tooltip.js ➔ ... ➔ _cleanTipClass 0 8 3
A tooltip.js ➔ ... ➔ _objectSpread 18 18 4
A tooltip.js ➔ ... ➔ _createClass 0 5 3
A tooltip.js ➔ ... ➔ _defineProperty 0 14 2
B tooltip.js ➔ ... ➔ toggle 0 31 6
B tooltip.js ➔ ... ➔ sanitizeHtml 0 40 6
B tooltip.js ➔ ... ➔ _enter 0 32 8
A tooltip.js ➔ ... ➔ _getDelegateConfig 0 13 4
B tooltip.js ➔ ... ➔ _getConfig 0 32 7
A tooltip.js ➔ ... ➔ addAttachmentClass 0 3 1
A tooltip.js ➔ ... ➔ _getAttachment 0 3 1
A tooltip.js ➔ ... ➔ $.fn[NAME].noConflict 0 4 1
A tooltip.js ➔ ... ➔ hide 0 52 4
B tooltip.js ➔ ... ➔ _leave 0 31 7
A tooltip.js ➔ ... ➔ setContent 0 5 1
A tooltip.js ➔ ... ➔ Tooltip 0 22 2
A tooltip.js ➔ ... ➔ _jQueryInterface 24 24 1
A tooltip.js ➔ ... ➔ _setListeners 0 34 2
B tooltip.js ➔ ... ➔ Tooltip.constructor 24 607 1
A tooltip.js ➔ ... ➔ get 0 3 1
B tooltip.js ➔ ... ➔ setElementContent 0 24 8
A tooltip.js ➔ ... ➔ dispose 0 24 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/*!
2
  * Bootstrap tooltip.js v4.3.1 (https://getbootstrap.com/)
3
  * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5
  */
6
(function (global, factory) {
7
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('popper.js'), require('./util.js')) :
8
  typeof define === 'function' && define.amd ? define(['jquery', 'popper.js', './util.js'], factory) :
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
9
  (global = global || self, global.Tooltip = factory(global.jQuery, global.Popper, global.Util));
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable self is declared in the current environment, consider using typeof self === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
10
}(this, function ($, Popper, Util) { 'use strict';
11
12
  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
13
  Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper;
14
  Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util;
15
16
  function _defineProperties(target, props) {
17
    for (var i = 0; i < props.length; i++) {
18
      var descriptor = props[i];
19
      descriptor.enumerable = descriptor.enumerable || false;
20
      descriptor.configurable = true;
21
      if ("value" in descriptor) descriptor.writable = true;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
22
      Object.defineProperty(target, descriptor.key, descriptor);
23
    }
24
  }
25
26
  function _createClass(Constructor, protoProps, staticProps) {
27
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
28
    if (staticProps) _defineProperties(Constructor, staticProps);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
29
    return Constructor;
30
  }
31
32
  function _defineProperty(obj, key, value) {
33
    if (key in obj) {
34
      Object.defineProperty(obj, key, {
35
        value: value,
36
        enumerable: true,
37
        configurable: true,
38
        writable: true
39
      });
40
    } else {
41
      obj[key] = value;
42
    }
43
44
    return obj;
45
  }
46
47 View Code Duplication
  function _objectSpread(target) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
48
    for (var i = 1; i < arguments.length; i++) {
49
      var source = arguments[i] != null ? arguments[i] : {};
0 ignored issues
show
Best Practice introduced by
Comparing arguments.i to null using the != operator is not safe. Consider using !== instead.
Loading history...
50
      var ownKeys = Object.keys(source);
51
52
      if (typeof Object.getOwnPropertySymbols === 'function') {
53
        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
54
          return Object.getOwnPropertyDescriptor(source, sym).enumerable;
0 ignored issues
show
Bug introduced by
The variable source is changed as part of the for loop for example by arguments.i != null ? arguments.i: {} on line 49. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
55
        }));
56
      }
57
58
      ownKeys.forEach(function (key) {
59
        _defineProperty(target, key, source[key]);
0 ignored issues
show
Bug introduced by
The variable source is changed as part of the for loop for example by arguments.i != null ? arguments.i: {} on line 49. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
60
      });
61
    }
62
63
    return target;
64
  }
65
66
  /**
67
   * --------------------------------------------------------------------------
68
   * Bootstrap (v4.3.1): tools/sanitizer.js
69
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
70
   * --------------------------------------------------------------------------
71
   */
72
  var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];
73
  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
74
  var DefaultWhitelist = {
75
    // Global attributes allowed on any supplied element below.
76
    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
77
    a: ['target', 'href', 'title', 'rel'],
78
    area: [],
79
    b: [],
80
    br: [],
81
    col: [],
82
    code: [],
83
    div: [],
84
    em: [],
85
    hr: [],
86
    h1: [],
87
    h2: [],
88
    h3: [],
89
    h4: [],
90
    h5: [],
91
    h6: [],
92
    i: [],
93
    img: ['src', 'alt', 'title', 'width', 'height'],
94
    li: [],
95
    ol: [],
96
    p: [],
97
    pre: [],
98
    s: [],
99
    small: [],
100
    span: [],
101
    sub: [],
102
    sup: [],
103
    strong: [],
104
    u: [],
105
    ul: []
106
    /**
107
     * A pattern that recognizes a commonly useful subset of URLs that are safe.
108
     *
109
     * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
110
     */
111
112
  };
113
  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
114
  /**
115
   * A pattern that matches safe data URLs. Only matches image, video and audio types.
116
   *
117
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
118
   */
119
120
  var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
121
122
  function allowedAttribute(attr, allowedAttributeList) {
123
    var attrName = attr.nodeName.toLowerCase();
124
125
    if (allowedAttributeList.indexOf(attrName) !== -1) {
126
      if (uriAttrs.indexOf(attrName) !== -1) {
127
        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));
128
      }
129
130
      return true;
131
    }
132
133
    var regExp = allowedAttributeList.filter(function (attrRegex) {
134
      return attrRegex instanceof RegExp;
135
    }); // Check if a regular expression validates the attribute.
136
137
    for (var i = 0, l = regExp.length; i < l; i++) {
138
      if (attrName.match(regExp[i])) {
139
        return true;
140
      }
141
    }
142
143
    return false;
144
  }
145
146
  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
147
    if (unsafeHtml.length === 0) {
148
      return unsafeHtml;
149
    }
150
151
    if (sanitizeFn && typeof sanitizeFn === 'function') {
152
      return sanitizeFn(unsafeHtml);
153
    }
154
155
    var domParser = new window.DOMParser();
156
    var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
157
    var whitelistKeys = Object.keys(whiteList);
158
    var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));
159
160
    var _loop = function _loop(i, len) {
0 ignored issues
show
Unused Code introduced by
The parameter len is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
161
      var el = elements[i];
162
      var elName = el.nodeName.toLowerCase();
163
164
      if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {
165
        el.parentNode.removeChild(el);
166
        return "continue";
167
      }
168
169
      var attributeList = [].slice.call(el.attributes);
170
      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
171
      attributeList.forEach(function (attr) {
172
        if (!allowedAttribute(attr, whitelistedAttributes)) {
173
          el.removeAttribute(attr.nodeName);
174
        }
175
      });
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
176
    };
177
178
    for (var i = 0, len = elements.length; i < len; i++) {
179
      var _ret = _loop(i, len);
180
181
      if (_ret === "continue") continue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Unused Code introduced by
This continue has no effect on the loop flow and can be removed.
Loading history...
182
    }
183
184
    return createdDocument.body.innerHTML;
185
  }
186
187
  /**
188
   * ------------------------------------------------------------------------
189
   * Constants
190
   * ------------------------------------------------------------------------
191
   */
192
193
  var NAME = 'tooltip';
194
  var VERSION = '4.3.1';
195
  var DATA_KEY = 'bs.tooltip';
196
  var EVENT_KEY = "." + DATA_KEY;
197
  var JQUERY_NO_CONFLICT = $.fn[NAME];
198
  var CLASS_PREFIX = 'bs-tooltip';
199
  var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
200
  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
201
  var DefaultType = {
202
    animation: 'boolean',
203
    template: 'string',
204
    title: '(string|element|function)',
205
    trigger: 'string',
206
    delay: '(number|object)',
207
    html: 'boolean',
208
    selector: '(string|boolean)',
209
    placement: '(string|function)',
210
    offset: '(number|string|function)',
211
    container: '(string|element|boolean)',
212
    fallbackPlacement: '(string|array)',
213
    boundary: '(string|element)',
214
    sanitize: 'boolean',
215
    sanitizeFn: '(null|function)',
216
    whiteList: 'object'
217
  };
218
  var AttachmentMap = {
219
    AUTO: 'auto',
220
    TOP: 'top',
221
    RIGHT: 'right',
222
    BOTTOM: 'bottom',
223
    LEFT: 'left'
224
  };
225
  var Default = {
226
    animation: true,
227
    template: '<div class="tooltip" role="tooltip">' + '<div class="arrow"></div>' + '<div class="tooltip-inner"></div></div>',
228
    trigger: 'hover focus',
229
    title: '',
230
    delay: 0,
231
    html: false,
232
    selector: false,
233
    placement: 'top',
234
    offset: 0,
235
    container: false,
236
    fallbackPlacement: 'flip',
237
    boundary: 'scrollParent',
238
    sanitize: true,
239
    sanitizeFn: null,
240
    whiteList: DefaultWhitelist
241
  };
242
  var HoverState = {
243
    SHOW: 'show',
244
    OUT: 'out'
245
  };
246
  var Event = {
247
    HIDE: "hide" + EVENT_KEY,
248
    HIDDEN: "hidden" + EVENT_KEY,
249
    SHOW: "show" + EVENT_KEY,
250
    SHOWN: "shown" + EVENT_KEY,
251
    INSERTED: "inserted" + EVENT_KEY,
252
    CLICK: "click" + EVENT_KEY,
253
    FOCUSIN: "focusin" + EVENT_KEY,
254
    FOCUSOUT: "focusout" + EVENT_KEY,
255
    MOUSEENTER: "mouseenter" + EVENT_KEY,
256
    MOUSELEAVE: "mouseleave" + EVENT_KEY
257
  };
258
  var ClassName = {
259
    FADE: 'fade',
260
    SHOW: 'show'
261
  };
262
  var Selector = {
263
    TOOLTIP: '.tooltip',
264
    TOOLTIP_INNER: '.tooltip-inner',
265
    ARROW: '.arrow'
266
  };
267
  var Trigger = {
268
    HOVER: 'hover',
269
    FOCUS: 'focus',
270
    CLICK: 'click',
271
    MANUAL: 'manual'
272
    /**
273
     * ------------------------------------------------------------------------
274
     * Class Definition
275
     * ------------------------------------------------------------------------
276
     */
277
278
  };
279
280
  var Tooltip =
281
  /*#__PURE__*/
282
  function () {
283
    function Tooltip(element, config) {
284
      /**
285
       * Check for Popper dependency
286
       * Popper - https://popper.js.org
287
       */
288
      if (typeof Popper === 'undefined') {
289
        throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)');
290
      } // private
291
292
293
      this._isEnabled = true;
294
      this._timeout = 0;
295
      this._hoverState = '';
296
      this._activeTrigger = {};
297
      this._popper = null; // Protected
298
299
      this.element = element;
300
      this.config = this._getConfig(config);
301
      this.tip = null;
302
303
      this._setListeners();
304
    } // Getters
305
306
307
    var _proto = Tooltip.prototype;
308
309
    // Public
310
    _proto.enable = function enable() {
311
      this._isEnabled = true;
312
    };
313
314
    _proto.disable = function disable() {
315
      this._isEnabled = false;
316
    };
317
318
    _proto.toggleEnabled = function toggleEnabled() {
319
      this._isEnabled = !this._isEnabled;
320
    };
321
322
    _proto.toggle = function toggle(event) {
323
      if (!this._isEnabled) {
324
        return;
325
      }
326
327
      if (event) {
328
        var dataKey = this.constructor.DATA_KEY;
329
        var context = $(event.currentTarget).data(dataKey);
330
331
        if (!context) {
332
          context = new this.constructor(event.currentTarget, this._getDelegateConfig());
333
          $(event.currentTarget).data(dataKey, context);
334
        }
335
336
        context._activeTrigger.click = !context._activeTrigger.click;
337
338
        if (context._isWithActiveTrigger()) {
339
          context._enter(null, context);
340
        } else {
341
          context._leave(null, context);
342
        }
343
      } else {
344
        if ($(this.getTipElement()).hasClass(ClassName.SHOW)) {
345
          this._leave(null, this);
346
347
          return;
348
        }
349
350
        this._enter(null, this);
351
      }
352
    };
353
354
    _proto.dispose = function dispose() {
355
      clearTimeout(this._timeout);
356
      $.removeData(this.element, this.constructor.DATA_KEY);
357
      $(this.element).off(this.constructor.EVENT_KEY);
358
      $(this.element).closest('.modal').off('hide.bs.modal');
359
360
      if (this.tip) {
361
        $(this.tip).remove();
362
      }
363
364
      this._isEnabled = null;
365
      this._timeout = null;
366
      this._hoverState = null;
367
      this._activeTrigger = null;
368
369
      if (this._popper !== null) {
370
        this._popper.destroy();
371
      }
372
373
      this._popper = null;
374
      this.element = null;
375
      this.config = null;
376
      this.tip = null;
377
    };
378
379
    _proto.show = function show() {
380
      var _this = this;
381
382
      if ($(this.element).css('display') === 'none') {
383
        throw new Error('Please use show on visible elements');
384
      }
385
386
      var showEvent = $.Event(this.constructor.Event.SHOW);
387
388
      if (this.isWithContent() && this._isEnabled) {
389
        $(this.element).trigger(showEvent);
390
        var shadowRoot = Util.findShadowRoot(this.element);
391
        var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);
392
393
        if (showEvent.isDefaultPrevented() || !isInTheDom) {
394
          return;
395
        }
396
397
        var tip = this.getTipElement();
398
        var tipId = Util.getUID(this.constructor.NAME);
399
        tip.setAttribute('id', tipId);
400
        this.element.setAttribute('aria-describedby', tipId);
401
        this.setContent();
402
403
        if (this.config.animation) {
404
          $(tip).addClass(ClassName.FADE);
405
        }
406
407
        var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
408
409
        var attachment = this._getAttachment(placement);
410
411
        this.addAttachmentClass(attachment);
412
413
        var container = this._getContainer();
414
415
        $(tip).data(this.constructor.DATA_KEY, this);
416
417
        if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
418
          $(tip).appendTo(container);
419
        }
420
421
        $(this.element).trigger(this.constructor.Event.INSERTED);
422
        this._popper = new Popper(this.element, tip, {
423
          placement: attachment,
424
          modifiers: {
425
            offset: this._getOffset(),
426
            flip: {
427
              behavior: this.config.fallbackPlacement
428
            },
429
            arrow: {
430
              element: Selector.ARROW
431
            },
432
            preventOverflow: {
433
              boundariesElement: this.config.boundary
434
            }
435
          },
436
          onCreate: function onCreate(data) {
437
            if (data.originalPlacement !== data.placement) {
438
              _this._handlePopperPlacementChange(data);
439
            }
440
          },
441
          onUpdate: function onUpdate(data) {
442
            return _this._handlePopperPlacementChange(data);
443
          }
444
        });
445
        $(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra
446
        // empty mouseover listeners to the body's immediate children;
447
        // only needed because of broken event delegation on iOS
448
        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
449
450
        if ('ontouchstart' in document.documentElement) {
451
          $(document.body).children().on('mouseover', null, $.noop);
452
        }
453
454
        var complete = function complete() {
455
          if (_this.config.animation) {
456
            _this._fixTransition();
457
          }
458
459
          var prevHoverState = _this._hoverState;
460
          _this._hoverState = null;
461
          $(_this.element).trigger(_this.constructor.Event.SHOWN);
462
463
          if (prevHoverState === HoverState.OUT) {
464
            _this._leave(null, _this);
465
          }
466
        };
467
468
        if ($(this.tip).hasClass(ClassName.FADE)) {
469
          var transitionDuration = Util.getTransitionDurationFromElement(this.tip);
470
          $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
471
        } else {
472
          complete();
473
        }
474
      }
475
    };
476
477
    _proto.hide = function hide(callback) {
478
      var _this2 = this;
479
480
      var tip = this.getTipElement();
481
      var hideEvent = $.Event(this.constructor.Event.HIDE);
482
483
      var complete = function complete() {
484
        if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
485
          tip.parentNode.removeChild(tip);
486
        }
487
488
        _this2._cleanTipClass();
489
490
        _this2.element.removeAttribute('aria-describedby');
491
492
        $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);
493
494
        if (_this2._popper !== null) {
495
          _this2._popper.destroy();
496
        }
497
498
        if (callback) {
499
          callback();
500
        }
501
      };
502
503
      $(this.element).trigger(hideEvent);
504
505
      if (hideEvent.isDefaultPrevented()) {
506
        return;
507
      }
508
509
      $(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra
510
      // empty mouseover listeners we added for iOS support
511
512
      if ('ontouchstart' in document.documentElement) {
513
        $(document.body).children().off('mouseover', null, $.noop);
514
      }
515
516
      this._activeTrigger[Trigger.CLICK] = false;
517
      this._activeTrigger[Trigger.FOCUS] = false;
518
      this._activeTrigger[Trigger.HOVER] = false;
519
520
      if ($(this.tip).hasClass(ClassName.FADE)) {
521
        var transitionDuration = Util.getTransitionDurationFromElement(tip);
522
        $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
523
      } else {
524
        complete();
525
      }
526
527
      this._hoverState = '';
528
    };
529
530
    _proto.update = function update() {
531
      if (this._popper !== null) {
532
        this._popper.scheduleUpdate();
533
      }
534
    } // Protected
535
    ;
536
537
    _proto.isWithContent = function isWithContent() {
538
      return Boolean(this.getTitle());
539
    };
540
541
    _proto.addAttachmentClass = function addAttachmentClass(attachment) {
542
      $(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
543
    };
544
545
    _proto.getTipElement = function getTipElement() {
546
      this.tip = this.tip || $(this.config.template)[0];
547
      return this.tip;
548
    };
549
550
    _proto.setContent = function setContent() {
551
      var tip = this.getTipElement();
552
      this.setElementContent($(tip.querySelectorAll(Selector.TOOLTIP_INNER)), this.getTitle());
553
      $(tip).removeClass(ClassName.FADE + " " + ClassName.SHOW);
554
    };
555
556
    _proto.setElementContent = function setElementContent($element, content) {
557
      if (typeof content === 'object' && (content.nodeType || content.jquery)) {
558
        // Content is a DOM node or a jQuery
559
        if (this.config.html) {
560
          if (!$(content).parent().is($element)) {
561
            $element.empty().append(content);
562
          }
563
        } else {
564
          $element.text($(content).text());
565
        }
566
567
        return;
568
      }
569
570
      if (this.config.html) {
571
        if (this.config.sanitize) {
572
          content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);
573
        }
574
575
        $element.html(content);
576
      } else {
577
        $element.text(content);
578
      }
579
    };
580
581
    _proto.getTitle = function getTitle() {
582
      var title = this.element.getAttribute('data-original-title');
583
584
      if (!title) {
585
        title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
586
      }
587
588
      return title;
589
    } // Private
590
    ;
591
592
    _proto._getOffset = function _getOffset() {
593
      var _this3 = this;
594
595
      var offset = {};
596
597
      if (typeof this.config.offset === 'function') {
598
        offset.fn = function (data) {
599
          data.offsets = _objectSpread({}, data.offsets, _this3.config.offset(data.offsets, _this3.element) || {});
600
          return data;
601
        };
602
      } else {
603
        offset.offset = this.config.offset;
604
      }
605
606
      return offset;
607
    };
608
609
    _proto._getContainer = function _getContainer() {
610
      if (this.config.container === false) {
611
        return document.body;
612
      }
613
614
      if (Util.isElement(this.config.container)) {
615
        return $(this.config.container);
616
      }
617
618
      return $(document).find(this.config.container);
619
    };
620
621
    _proto._getAttachment = function _getAttachment(placement) {
622
      return AttachmentMap[placement.toUpperCase()];
623
    };
624
625
    _proto._setListeners = function _setListeners() {
626
      var _this4 = this;
627
628
      var triggers = this.config.trigger.split(' ');
629
      triggers.forEach(function (trigger) {
630
        if (trigger === 'click') {
631
          $(_this4.element).on(_this4.constructor.Event.CLICK, _this4.config.selector, function (event) {
632
            return _this4.toggle(event);
633
          });
634
        } else if (trigger !== Trigger.MANUAL) {
635
          var eventIn = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSEENTER : _this4.constructor.Event.FOCUSIN;
636
          var eventOut = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSELEAVE : _this4.constructor.Event.FOCUSOUT;
637
          $(_this4.element).on(eventIn, _this4.config.selector, function (event) {
638
            return _this4._enter(event);
639
          }).on(eventOut, _this4.config.selector, function (event) {
640
            return _this4._leave(event);
641
          });
642
        }
643
      });
644
      $(this.element).closest('.modal').on('hide.bs.modal', function () {
645
        if (_this4.element) {
646
          _this4.hide();
647
        }
648
      });
649
650
      if (this.config.selector) {
651
        this.config = _objectSpread({}, this.config, {
652
          trigger: 'manual',
653
          selector: ''
654
        });
655
      } else {
656
        this._fixTitle();
657
      }
658
    };
659
660
    _proto._fixTitle = function _fixTitle() {
661
      var titleType = typeof this.element.getAttribute('data-original-title');
662
663
      if (this.element.getAttribute('title') || titleType !== 'string') {
664
        this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
665
        this.element.setAttribute('title', '');
666
      }
667
    };
668
669
    _proto._enter = function _enter(event, context) {
670
      var dataKey = this.constructor.DATA_KEY;
671
      context = context || $(event.currentTarget).data(dataKey);
672
673
      if (!context) {
674
        context = new this.constructor(event.currentTarget, this._getDelegateConfig());
675
        $(event.currentTarget).data(dataKey, context);
676
      }
677
678
      if (event) {
679
        context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
680
      }
681
682
      if ($(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) {
683
        context._hoverState = HoverState.SHOW;
684
        return;
685
      }
686
687
      clearTimeout(context._timeout);
688
      context._hoverState = HoverState.SHOW;
689
690
      if (!context.config.delay || !context.config.delay.show) {
691
        context.show();
692
        return;
693
      }
694
695
      context._timeout = setTimeout(function () {
696
        if (context._hoverState === HoverState.SHOW) {
697
          context.show();
698
        }
699
      }, context.config.delay.show);
700
    };
701
702
    _proto._leave = function _leave(event, context) {
703
      var dataKey = this.constructor.DATA_KEY;
704
      context = context || $(event.currentTarget).data(dataKey);
705
706
      if (!context) {
707
        context = new this.constructor(event.currentTarget, this._getDelegateConfig());
708
        $(event.currentTarget).data(dataKey, context);
709
      }
710
711
      if (event) {
712
        context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
713
      }
714
715
      if (context._isWithActiveTrigger()) {
716
        return;
717
      }
718
719
      clearTimeout(context._timeout);
720
      context._hoverState = HoverState.OUT;
721
722
      if (!context.config.delay || !context.config.delay.hide) {
723
        context.hide();
724
        return;
725
      }
726
727
      context._timeout = setTimeout(function () {
728
        if (context._hoverState === HoverState.OUT) {
729
          context.hide();
730
        }
731
      }, context.config.delay.hide);
732
    };
733
734
    _proto._isWithActiveTrigger = function _isWithActiveTrigger() {
735
      for (var trigger in this._activeTrigger) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
736
        if (this._activeTrigger[trigger]) {
737
          return true;
738
        }
739
      }
740
741
      return false;
742
    };
743
744
    _proto._getConfig = function _getConfig(config) {
745
      var dataAttributes = $(this.element).data();
746
      Object.keys(dataAttributes).forEach(function (dataAttr) {
747
        if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {
748
          delete dataAttributes[dataAttr];
749
        }
750
      });
751
      config = _objectSpread({}, this.constructor.Default, dataAttributes, typeof config === 'object' && config ? config : {});
752
753
      if (typeof config.delay === 'number') {
754
        config.delay = {
755
          show: config.delay,
756
          hide: config.delay
757
        };
758
      }
759
760
      if (typeof config.title === 'number') {
761
        config.title = config.title.toString();
762
      }
763
764
      if (typeof config.content === 'number') {
765
        config.content = config.content.toString();
766
      }
767
768
      Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
769
770
      if (config.sanitize) {
771
        config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);
772
      }
773
774
      return config;
775
    };
776
777
    _proto._getDelegateConfig = function _getDelegateConfig() {
778
      var config = {};
779
780
      if (this.config) {
781
        for (var key in this.config) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
782
          if (this.constructor.Default[key] !== this.config[key]) {
783
            config[key] = this.config[key];
784
          }
785
        }
786
      }
787
788
      return config;
789
    };
790
791
    _proto._cleanTipClass = function _cleanTipClass() {
792
      var $tip = $(this.getTipElement());
793
      var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
794
795
      if (tabClass !== null && tabClass.length) {
796
        $tip.removeClass(tabClass.join(''));
797
      }
798
    };
799
800
    _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {
801
      var popperInstance = popperData.instance;
802
      this.tip = popperInstance.popper;
803
804
      this._cleanTipClass();
805
806
      this.addAttachmentClass(this._getAttachment(popperData.placement));
807
    };
808
809
    _proto._fixTransition = function _fixTransition() {
810
      var tip = this.getTipElement();
811
      var initConfigAnimation = this.config.animation;
812
813
      if (tip.getAttribute('x-placement') !== null) {
814
        return;
815
      }
816
817
      $(tip).removeClass(ClassName.FADE);
818
      this.config.animation = false;
819
      this.hide();
820
      this.show();
821
      this.config.animation = initConfigAnimation;
822
    } // Static
823
    ;
824
825 View Code Duplication
    Tooltip._jQueryInterface = function _jQueryInterface(config) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
826
      return this.each(function () {
827
        var data = $(this).data(DATA_KEY);
828
829
        var _config = typeof config === 'object' && config;
830
831
        if (!data && /dispose|hide/.test(config)) {
832
          return;
833
        }
834
835
        if (!data) {
836
          data = new Tooltip(this, _config);
837
          $(this).data(DATA_KEY, data);
838
        }
839
840
        if (typeof config === 'string') {
841
          if (typeof data[config] === 'undefined') {
842
            throw new TypeError("No method named \"" + config + "\"");
843
          }
844
845
          data[config]();
846
        }
847
      });
848
    };
849
850
    _createClass(Tooltip, null, [{
851
      key: "VERSION",
852
      get: function get() {
853
        return VERSION;
854
      }
855
    }, {
856
      key: "Default",
857
      get: function get() {
858
        return Default;
859
      }
860
    }, {
861
      key: "NAME",
862
      get: function get() {
863
        return NAME;
864
      }
865
    }, {
866
      key: "DATA_KEY",
867
      get: function get() {
868
        return DATA_KEY;
869
      }
870
    }, {
871
      key: "Event",
872
      get: function get() {
873
        return Event;
874
      }
875
    }, {
876
      key: "EVENT_KEY",
877
      get: function get() {
878
        return EVENT_KEY;
879
      }
880
    }, {
881
      key: "DefaultType",
882
      get: function get() {
883
        return DefaultType;
884
      }
885
    }]);
886
887
    return Tooltip;
888
  }();
889
  /**
890
   * ------------------------------------------------------------------------
891
   * jQuery
892
   * ------------------------------------------------------------------------
893
   */
894
895
896
  $.fn[NAME] = Tooltip._jQueryInterface;
897
  $.fn[NAME].Constructor = Tooltip;
898
899
  $.fn[NAME].noConflict = function () {
900
    $.fn[NAME] = JQUERY_NO_CONFLICT;
901
    return Tooltip._jQueryInterface;
902
  };
903
904
  return Tooltip;
905
906
}));
907
//# sourceMappingURL=tooltip.js.map
908